/*
 *  ttf文件解析,依赖 libfreetype
 *  注意库的头文件需包含到 -I../include/freetype2
 */
#include <stdio.h>
#include <unistd.h>

/* 官方宏定义式的头文件包含 */
#include "ft2build.h"
#include FT_FREETYPE_H
#include FT_MULTIPLE_MASTERS_H
#include FT_GLYPH_H
#include FT_OUTLINE_H

#include "lib_freetype_adapt.h"

/* 基线高为字体高的1/8 (在矩阵内的上下偏移量) */
#define BASELINE_OF_HEIGHT(h) (h / 8)

/* ascii输出时的宽高比例4:5 (胖瘦设置) */
#define ASCII_WIDTH_OF_HEIGHT(h) (h * 4 / 5)

#define FREETYPE_INFO(...) fprintf(stdout, "\033[32m[FREETYPE_INFO] %s(%d): \033[0m", __FUNCTION__, __LINE__),fprintf(stdout, __VA_ARGS__)
#define FREETYPE_ERR(...) fprintf(stderr, "\033[31m[FREETYPE_ERR] %s(%d): \033[0m", __FUNCTION__, __LINE__),fprintf(stderr, __VA_ARGS__)

typedef struct
{
    FT_Library libHandle;
    FT_Face faceHandles[100];
} LibFtStruct;

/* 0~90度的sin()函数值查表: sin(n)*0x10000 */
static const int32_t _LibFtDegreeToSin[91] = {
0, 1143, 2287, 3429, 4571, 5711, 6850, 7986, 9120, 10252, 
11380, 12504, 13625, 14742, 15854, 16961, 18064, 19160, 20251, 21336, 
22414, 23486, 24550, 25606, 26655, 27696, 28729, 29752, 30767, 31772, 
32767, 33753, 34728, 35693, 36647, 37589, 38521, 39440, 40347, 41243, 
42125, 42995, 43852, 44695, 45525, 46340, 47142, 47929, 48702, 49460, 
50203, 50931, 51643, 52339, 53019, 53683, 54331, 54963, 55577, 56175, 
56755, 57319, 57864, 58393, 58903, 59395, 59870, 60326, 60763, 61183, 
61583, 61965, 62328, 62672, 62997, 63302, 63589, 63856, 64103, 64331, 
64540, 64729, 64898, 65047, 65176, 65286, 65376, 65446, 65496, 65526, 
65536};

/*
 *  utf8转unicode
 *  返回: 下一个检索位置
 */
static uint8_t* _LibFtUtf8ToUnicode(uint8_t* utf8, FT_ULong* unicode)
{
    /*
     * -------unicode--------|-----utf8-----
     * 0000 0000 ~ 0000 007F | 0xxxxxxx
     * 0000 0080 ~ 0000 07FF | 110xxxxx 10xxxxxx
     * 0000 0800 ~ 0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
     * 0001 0000 ~ 0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
     */

    if (utf8[0] < 0x80)
    {
        *unicode = utf8[0];
        return utf8 + 1;
    }
    else if (utf8[0] < 0xE0 && utf8[1] > 0x7F)
    {
        *unicode = ((utf8[0] & 0x1F) << 6) | (utf8[1] & 0x3F);
        return utf8 + 2;
    }
    else if (utf8[0] < 0xF0 && utf8[1] > 0x7F && utf8[2] > 0x7F)
    {
        *unicode = ((utf8[0] & 0x0F) << 12) | ((utf8[1] & 0x3F) << 6) | (utf8[2] & 0x3F);
        return utf8 + 3;
    }
    else if (utf8[0] < 0xF8 && utf8[1] > 0x7F && utf8[2] > 0x7F && utf8[3] > 0x7F)
    {
        *unicode = ((utf8[0] & 0x07) << 18) | ((utf8[1] & 0x3F) << 12) | ((utf8[2] & 0x3F) << 6) | (utf8[3] & 0x3F);
        return utf8 + 4;
    }

    FREETYPE_ERR("incorrect utf8 code [%02X.%02X.%02X.%02X] \r\n", utf8[0], utf8[1], utf8[2], utf8[3]);
    *unicode = '?';
    return utf8 + 1;
}

/*
 *  根据font、unicode计算当前字型的宽高(不是最终内存的宽高)
 *  返回: 加粗
 */
static int32_t _LibFtFontParse(
    int32_t font, FT_ULong unicode, int32_t* width, int32_t* height, int32_t* baseLineHeight)
{
    font /= 100;

    *height = font / 100;
    if (*height == 0)
        return -1;

    if (unicode < 0x80)
        *width = ASCII_WIDTH_OF_HEIGHT(*height);
    else
        *width = *height;

    *baseLineHeight = BASELINE_OF_HEIGHT(*height);
    return font % 100;
}

/* 旋转角度转2x2矩阵 */
static FT_Matrix _LibFtAngleToMatrix(int32_t angle)
{
    FT_Matrix matrix;

    /* 转换为0~359范围 */
    angle %= 360;
    if (angle < 0)
        angle += 360;

    /* 先定角度,再按照象限定符号 */
    if (angle < 90)
    {
        matrix.xx = (FT_Fixed)_LibFtDegreeToSin[90 - angle];
        matrix.xy = -(FT_Fixed)_LibFtDegreeToSin[angle];
    }
    else if (angle < 180)
    {
        angle = 180 - angle;
        matrix.xx = -(FT_Fixed)_LibFtDegreeToSin[90 - angle];
        matrix.xy = -(FT_Fixed)_LibFtDegreeToSin[angle];
    }
    else if (angle < 270)
    {
        angle = angle - 180;
        matrix.xx = -(FT_Fixed)_LibFtDegreeToSin[90 - angle];
        matrix.xy = (FT_Fixed)_LibFtDegreeToSin[angle];
    }
    else
    {
        angle = 360 - angle;
        matrix.xx = (FT_Fixed)_LibFtDegreeToSin[90 - angle];
        matrix.xy = (FT_Fixed)_LibFtDegreeToSin[angle];
    }
    matrix.yx = -matrix.xy;
    matrix.yy = matrix.xx;

    /* -------------- 原式子 --------------
    * matrix.xx = (FT_Fixed)( cos( rad ) * 0x10000L );
    * matrix.xy = (FT_Fixed)(-sin( rad ) * 0x10000L );
    * matrix.yx = (FT_Fixed)( sin( rad ) * 0x10000L );
    * matrix.yy = (FT_Fixed)( cos( rad ) * 0x10000L );
    */
   return matrix;
}

void *LibFtInit()
{
    LibFtStruct *lfs = (LibFtStruct *)calloc(1, sizeof(LibFtStruct));

    if (FT_Init_FreeType(&lfs->libHandle) != 0)
    {
        FREETYPE_ERR("FT_Init_FreeType err \r\n");
        free(lfs);
        return NULL;
    }

    return lfs;
}

void LibFtRelease(void* handle)
{
    int32_t i;
    LibFtStruct *lfs = (LibFtStruct *)handle;
    if (!lfs)
        return;

    for (i = 0; i < 100; i++)
    {
        if (lfs->faceHandles[i])
            FT_Done_Face(lfs->faceHandles[i]);
    }

    if (lfs->libHandle)
        FT_Done_FreeType(lfs->libHandle);

    free(lfs);
}

int32_t LibFtAddFontFile(FT_HANDLE handle, const char* ttfFile, int32_t id)
{
    LibFtStruct *lfs = (LibFtStruct *)handle;
    if (!lfs || id < 0 || id >= 100)
        return -1;
    
    if (lfs->faceHandles[id])
        FT_Done_Face(lfs->faceHandles[id]);
    lfs->faceHandles[id] = NULL;

    if (FT_New_Face(lfs->libHandle, ttfFile, 0, &lfs->faceHandles[id]) != 0)
    {
        lfs->faceHandles[id] = NULL;
        FREETYPE_ERR("FT_New_Face err : %s \r\n", ttfFile);
        return -1;
    }

    return 0;
}

const char* LibFtGetMapByUtf8(
    FT_HANDLE handle,
    const char* utf8,
    int32_t font,
    int32_t angle,
    FtBitMap* map,
    bool isGrayMap)
{
    LibFtStruct *lfs = (LibFtStruct *)handle;
    FT_Face faceHandle = NULL;
    FT_ULong unicode = 0;
    /* 字体参数 */
    int32_t width = 0;
    int32_t height = 0;
    int32_t bold = 0;
    /* 基线高 */
    int32_t baseLineHeight = 0;
    /* 最终返回 */
    const char* ret = NULL;
    /* 2x2旋转矩阵 */
    FT_Matrix matrix;

    do
    {
        /* map指针检查 */
        if (!map)
            break;
        else if (map->bitMap)
            free(map->bitMap);
        memset(map, 0, sizeof(FtBitMap));

        /* 指针检查 */
        if (!utf8)
            break;

        if (!lfs)
        {
            FREETYPE_ERR("not initialize \r\n");
            break;
        }

        faceHandle = lfs->faceHandles[font%100];
        if (!faceHandle)
        {
            FREETYPE_ERR("not add ttfFile(id/%d) \r\n", font%100);
            break;
        }

        /* utf8 转 unicode */
        ret = (const char*)_LibFtUtf8ToUnicode((uint8_t *)utf8, &unicode);
        if (unicode < ' ')
            break;

        /* 解析: 宽/高/加粗 */
        bold = _LibFtFontParse(font, unicode, &width, &height, &baseLineHeight);

        /* 设置字体尺寸 */
        // if (FT_Set_Char_Size(faceHandle, width << 6, height << 6, 72, 72) != 0)
        if (FT_Set_Pixel_Sizes(faceHandle, width, height) != 0)
        {
            FREETYPE_ERR("FT_Set_Pixel_Sizes failed \r\n");
            break;
        }

        /* 旋转 */
        if (angle)
        {
            matrix = _LibFtAngleToMatrix(angle);
            FT_Set_Transform(faceHandle, &matrix, NULL);
        }

        /* 检索字形索引,装载字形图像到字形(将会抹掉先前的字形图像) */
        if (FT_Load_Glyph(faceHandle, FT_Get_Char_Index(faceHandle, unicode), FT_LOAD_DEFAULT) != 0)
        {
            FREETYPE_ERR("FT_Load_Glyph failed \r\n");
            break;
        }

        /* 设置加粗量 */
        if (FT_Outline_Embolden(&faceHandle->glyph->outline, bold << 6) != 0)
        {
            FREETYPE_ERR("FT_Outline_Embolden failed \r\n");
            break;
        }

        /* 建议的横向移动量 */
        map->width = faceHandle->glyph->advance.x >> 6;
        map->height = height;

        /* 获取位图 FT_RENDER_MODE_NORMAL:灰度图, FT_RENDER_MODE_MONO:黑白位图 */
        if (FT_Render_Glyph(faceHandle->glyph, isGrayMap ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO) == 0)
        {
            /* 位图拷贝 */
            map->bitMap = (uint8_t *)calloc(
                (faceHandle->glyph->bitmap.rows + 1) * faceHandle->glyph->bitmap.pitch, 1);
            memcpy(map->bitMap, faceHandle->glyph->bitmap.buffer,
                faceHandle->glyph->bitmap.rows * faceHandle->glyph->bitmap.pitch);
            /* 位图每行字节数 */
            map->lineByte = faceHandle->glyph->bitmap.pitch;
            /* 位图宽高 */
            map->bitWidth = faceHandle->glyph->bitmap.width;
            if (map->width < map->bitWidth)
                map->width = map->bitWidth;
            map->bitHeight = faceHandle->glyph->bitmap.rows;
            if (map->height < map->bitHeight)
                map->height = map->bitHeight;
            /* 位图在点阵左上角绘制位置 */
            map->bitLeft = (map->width - map->bitWidth) / 2;
            map->bitTop = map->height - map->bitHeight;
            if (map->bitTop > baseLineHeight)
                map->bitTop -= baseLineHeight; /* 保证统一基线高度 */
            else
                map->bitTop /= 2; /* 位图较高时,整体稍微下调(吃入部分基线) */

            // FREETYPE_INFO("%dx%d, left/%d, top/%d, lb/%d \r\n",
            //     faceHandle->glyph->bitmap.width,
            //     faceHandle->glyph->bitmap.rows,
            //     faceHandle->glyph->bitmap_left,
            //     faceHandle->glyph->bitmap_top,
            //     faceHandle->glyph->bitmap.pitch);
        }
        else
            FREETYPE_ERR("FT_Render_Glyph failed \r\n");
     
    } while (0);

    return ret;
}

int32_t LibFtGetSizeByUtf8(
    FT_HANDLE handle,
    const char *utf8,
    int32_t font,
    int32_t spaceX,
    int32_t spaceY,
    int32_t lineLimit,
    int32_t angle,
    int32_t* retW,
    int32_t* retH)
{
    LibFtStruct* lfs = (LibFtStruct*)handle;
    FT_Face faceHandle = NULL;
    FT_ULong unicode = 0;
    uint8_t* pUtf8 = (uint8_t*)utf8;
    /* 字体参数和基线高 */
    int32_t width = 0;
    int32_t height = 0;
    int32_t baseLineHeight = 0;
    /* 解析返回 */
    int32_t retWidth = 0;
    int32_t charWidth = 0;
    int32_t retWidthMax = 0;
    int32_t retHeight = font / 10000;
    int32_t fontSize = font / 10000;
    /* 2x2旋转矩阵 */
    FT_Matrix matrix;

    /* 指针检查 */
    if (!lfs)
        return -1;
    
    faceHandle = lfs->faceHandles[font%100];
    if (!faceHandle)
    {
        FREETYPE_ERR("not add ttfFile(id/%d) \r\n", font%100);
        return -1;
    }

    /* 计算旋转矩阵 */
    if (angle)
        matrix = _LibFtAngleToMatrix(angle);

    while (*pUtf8)
    {
        /* utf8 转 unicode */
        pUtf8 = _LibFtUtf8ToUnicode(pUtf8, &unicode);

        /* 得到字符宽度 */
        if (unicode < ' ')
        {
            if (unicode == '\t')
                charWidth = fontSize * 2 + spaceX;
            else if (unicode == '\n')
                charWidth = -1;
            else
                charWidth = 0;
        }
        else
        {
            /* 解析: 宽/高/加粗 */
            _LibFtFontParse(font, unicode, &width, &height, &baseLineHeight);
        
            /* 设置字体尺寸 */
            // if (FT_Set_Char_Size(faceHandle, width << 6, height << 6, 72, 72) != 0)
            if (FT_Set_Pixel_Sizes(faceHandle, width, height) != 0)
            {
                FREETYPE_ERR("FT_Set_Pixel_Sizes failed \r\n");
                goto exit_err;
            }

            /* 旋转 */
            if (angle)
                FT_Set_Transform(faceHandle, &matrix, NULL);

            /* 从字符码检索字形索引,装载字形图像到字形槽(将会抹掉先前的字形图像) */
            if (FT_Load_Glyph(faceHandle, FT_Get_Char_Index(faceHandle, unicode), FT_LOAD_NO_BITMAP) != 0)
            {
                FREETYPE_ERR("FT_Load_Glyph failed \r\n");
                goto exit_err;
            }

            /* 实际字符宽度 */
            charWidth =  faceHandle->glyph->advance.x >> 6;
            if (charWidth < 0 || charWidth < faceHandle->glyph->bitmap.width)
                charWidth = faceHandle->glyph->bitmap.width;
        }
        /* 得到最终字型宽 -1表示换行 */
        if (charWidth > 0)
        {
            /* 行宽超出 lineLimit, 强制换行 */
            if (lineLimit > 0 && retWidth + charWidth > lineLimit)
            {
                /* 更新行宽峰值 */
                retWidthMax = lineLimit;
                /* 换行 */
                retWidth = charWidth;
                retHeight += (fontSize + spaceY);
            }
            else
                retWidth += (charWidth + spaceX);
        }
        else if (charWidth == -1)
        {
            /* 更新行宽峰值(如果比较大的话) */
            if (retWidth > retWidthMax)
                retWidthMax = retWidth;
            /* 换行 */
            retWidth = 0;
            retHeight += (fontSize + spaceY);
        }
    }

    /* 返回 */
    if (retH)
        *retH = retHeight;
    if (retW)
    {
        if (retWidth > retWidthMax)
            *retW = retWidth;
        else
            *retW = retWidthMax;
        if (*retW > spaceX)
            *retW -= spaceX;
    }

    return 0;
exit_err:
    return -1;
}
